package com.diana.aop;

import com.diana.common.Utils;
import com.diana.service.ManagerLogService;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.javassist.ClassClassPath;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.javassist.bytecode.LocalVariableAttribute;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class MylogAspect {

    Logger log = LoggerFactory.getLogger(MylogAspect.class);

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ManagerLogService managerLogService;

    private MylogAspect(){
        log.info("MylogAspect init()");
    }

    @Pointcut("@annotation(com.diana.aop.Mylog)")
    public void Aspect(){

    }

    @After("Aspect()")
    public void doAfter(JoinPoint joinPoint){
        try {
            String managerId = request.getHeader("managerId");
            if(!Utils.isNullOrEmpty(managerId)){
                String managerIp = Utils.getRemoteHost(request);
                String remark = getRemark(joinPoint);
                //@requestBody从流里边拿参数 且只能拿一次
                //String param = JSON.toJSONString(request.getParameterMap());
                String param = "";
                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(request.getReader());
                    param = reader.readLine();
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    if(reader !=null){
                        reader.close();
                    }
                }
                Map<String,Object> map = new HashMap<>();
                map.put("managerId",managerId);
                map.put("managerIp",managerIp);
                map.put("remark",remark);
                map.put("param",param);
                String reg = managerLogService.putLog(map);
                if(reg.contains("0001")){
                    log.warn("MylogAspect write log fail");
                }
            }else{
                log.warn("MylogAspect write log fail,Missing header");
            }
        }catch (Exception e){
            log.error("MylogAspect write log error:{}",e);
        }
    }

    /**
     * 获取remark
     * @param joinPoint
     * @return
     * @throws Exception
     */
    public static String getRemark(JoinPoint joinPoint)throws  Exception{
        /*String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String remark = "";
        for (Method method:methods){
            if(method.getName().equals(methodName)){
                Class [] types = method.getParameterTypes();
                if(types.length==args.length){
                    remark = method.getAnnotation(Mylog.class).remark();
                    break;
                }
            }
        }*/
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        String remark = method.getAnnotation(Mylog.class).remark();
        return remark;
    }

    /**
     * 获取方法入参变量名
     *
     * @param cls        触发的类
     * @param methodName 触发的方法名
     * @param include    需要打印的变量名
     * @return
     * @throws Exception
     */
    private Map<String, Object> getMethodParamNames(Class cls,String methodName, String include) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(cls));
        CtMethod cm = pool.get(cls.getName()).getDeclaredMethod(methodName);
        LocalVariableAttribute attr = (LocalVariableAttribute) cm
                .getMethodInfo().getCodeAttribute()
                .getAttribute(LocalVariableAttribute.tag);

        if (attr == null) {
            throw new Exception("attr is null");
        } else {
            Map<String, Object> paramNames = new HashMap<>();
            int paramNamesLen = cm.getParameterTypes().length;
            int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
            if (StringUtils.isEmpty(include)) {
                for (int i = 0; i < paramNamesLen; i++) {
                    paramNames.put(attr.variableName(i + pos), i);
                }
            } else { // 若include不为空
                for (int i = 0; i < paramNamesLen; i++) {
                    String paramName = attr.variableName(i + pos);
                    if (include.indexOf(paramName) > -1) {
                        paramNames.put(paramName, i);
                    }
                }
            }
            return paramNames;
        }
    }
}
